package de.invesdwin.util.lang;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/**
* Is ascending internally
*/
@Immutable
public abstract class ADelegateComparator<E> implements Comparator<Object> {
public static final ADelegateComparator<Object> DEFAULT_COMPARATOR = new ADelegateComparator<Object>() {
@Override
protected Comparable<?> getCompareCriteria(final Object e) {
return (Comparable<?>) e;
}
};
private final Class<E> genericType;
public ADelegateComparator() {
this.genericType = findGenericType();
}
/**
* Null never reaches this method. This is ensured internally.
*/
protected abstract Comparable<?> getCompareCriteria(@Nonnull final E e);
private Comparable<?> getCompareCriteriaNullsafe(final E e) {
if (e == null) {
return null;
} else {
return getCompareCriteria(e);
}
}
@Override
@SuppressWarnings("unchecked")
public final int compare(final Object o1, final Object o2) {
if (!genericType.isInstance(o1)) {
return -1;
} else if (!(genericType.isInstance(o2))) {
return 1;
}
final E e1 = (E) o1;
final E e2 = (E) o2;
final Comparable<Object> c1 = (Comparable<Object>) getCompareCriteriaNullsafe(e1);
final Comparable<Object> c2 = (Comparable<Object>) getCompareCriteriaNullsafe(e2);
if (c1 == null) {
if (isNullFirst()) {
return 1;
} else {
return -1;
}
} else if (c2 == null) {
if (isNullFirst()) {
return -1;
} else {
return 1;
}
} else {
return compare(c1, c2);
}
}
protected boolean isNullFirst() {
return false;
}
protected int compare(final Comparable<Object> c1, final Comparable<Object> c2) {
return c1.compareTo(c2);
}
public Comparator<Object> asDescending() {
return new Comparator<Object>() {
@Override
public int compare(final Object o1, final Object o2) {
final int compare = ADelegateComparator.this.compare(o1, o2);
if (compare < 0) {
return 1;
} else if (compare > 0) {
return -1;
} else {
return 0;
}
};
};
}
public <T extends E> void sort(final List<? extends T> list, final boolean ascending) {
if (list == null || list.size() == 0) {
return;
}
final Comparator<Object> comparator;
if (ascending) {
comparator = this;
} else {
comparator = asDescending();
}
Collections.sort(list, comparator);
}
/**
* Checks all elements
*/
public <T extends E> void assertOrder(final List<? extends T> list, final boolean ascending) {
if (list == null || list.size() == 0) {
return;
}
final Comparator<Object> comparator;
if (ascending) {
comparator = this;
} else {
comparator = asDescending();
}
T previousE = null;
for (final T e : list) {
if (previousE == null) {
previousE = e;
} else {
final int compareResult = comparator.compare(e, previousE);
if (compareResult < 0) {
org.assertj.core.api.Assertions.assertThat(compareResult)
.as("No %s order: previousE [%s], e [%s]", ascending ? "ascending" : "descending",
previousE, e)
.isGreaterThanOrEqualTo(0);
}
}
}
}
/**
* Just checks the first and last element.
*/
public <T extends E> void assertOrderFast(final List<? extends T> list, final boolean ascending) {
if (list == null || list.size() == 0) {
return;
}
final Comparator<Object> comparator;
if (ascending) {
comparator = this;
} else {
comparator = asDescending();
}
final T firstE = list.get(0);
final T lastE = list.get(list.size() - 1);
final int compareResult = comparator.compare(lastE, firstE);
if (compareResult < 0) {
org.assertj.core.api.Assertions.assertThat(compareResult)
.as("No %s order!", ascending ? "ascending" : "descending")
.isGreaterThanOrEqualTo(0);
}
}
/**
* @see <a href="http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/">Source</a>
*/
@SuppressWarnings("unchecked")
protected Class<E> findGenericType() {
return (Class<E>) org.springframework.core.GenericTypeResolver.resolveTypeArgument(getClass(),
ADelegateComparator.class);
}
public void sortDescending(final List<? extends E> list) {
sort(list, false);
}
public void sortAscending(final List<? extends E> list) {
sort(list, true);
}
}